package com.yzmoney.common.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.net.ssl.SSLHandshakeException;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * Created with IntelliJ IDEA.
 * User: Administrator
 * Date: 13-9-13
 * Time: 下午12:05
 * To change this template use File | Settings | File Templates.
 */
public class HttpClientUtils {
	private static Logger logger = Logger.getLogger(HttpClientUtils.class);
	
    private static final String CHARSET_UTF8 = "UTF-8";
    private static final String CHARSET_GBK = "GBK";
    private static final String SSL_DEFAULT_SCHEME = "https";
    private static final int SSL_DEFAULT_PORT = 443;
    private static final int CONNECTION_TIMEOUT_MILLIS = 60000;
    private static final int SOCKET_TIMEOUT_MILLIS = 120000;

    //异常自动恢复处理, 使用HttpRequestRetryHandler接口实现请求的异常恢复
    private static HttpRequestRetryHandler requestRetryHandler = new HttpRequestRetryHandler() {
        //自定义的恢复策略
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            //设置恢复策略，在发生异常时候将自动重试3次
            if (executionCount >= 3) {
                //Do not retry if over max retry count
                return false;
            }
            if (exception instanceof NoHttpResponseException) {
                //Retry if the server dropped connection on us
                return true;
            }
            if (exception instanceof SSLHandshakeException) {
                //Do not retry on SSL handshake exception
                return false;
            }
            HttpRequest request = (HttpRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
            boolean idempotent = (request instanceof HttpEntityEnclosingRequest);
            if (!idempotent) {
                //Retry if the request is considered idempotent
                return true;
            }
            return false;
        }
    };

    private static ResponseHandler<String> stringResponseHandler = new ResponseHandler<String>() {
        // 自定义响应处理
        public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String contentCharset = EntityUtils.getContentCharSet(entity);
                String charset = contentCharset == null ? CHARSET_GBK : contentCharset;
                return new String(EntityUtils.toByteArray(entity), charset);
            } else {
                return null;
            }
        }
    };

    private static ResponseHandler<byte[]> byteArrayHandler = new ResponseHandler<byte[]>() {
        //自定义响应处理
        public byte[] handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                return EntityUtils.toByteArray(entity);
            } else {
                return null;
            }
        }
    };

    public static byte[] getBytes(String url) throws Exception {
        return (byte[]) get(url, null, null, byteArrayHandler);
    }

    public static byte[] getBytes(String url, Map<String, String> params) throws Exception {
        return (byte[]) get(url, params, null, byteArrayHandler);
    }

    public static String getString(String url) throws Exception {
        return (String) get(url, null, null, stringResponseHandler);
    }

    public static String getString(String url, Map<String, String> params) throws Exception {
        return (String) get(url, params, null, stringResponseHandler);
    }

    private static Object get(String url, Map<String, String> params, String requestCharset, ResponseHandler handler) {
        if (url == null || StringUtils.isEmpty(url)) {
            return null;
        }
        List<NameValuePair> qparams = getParamsList(params);
        if (qparams != null && 0 < qparams.size()) {
            requestCharset = (requestCharset == null ? CHARSET_UTF8 : requestCharset);
            String formatParams = URLEncodedUtils.format(qparams, requestCharset);
            int index = url.indexOf("?");
            url = index < 0 ? (url + "?" + formatParams) : (url.substring(0, index + 1) + formatParams);
        }
        DefaultHttpClient httpclient = null;
        HttpGet hg = null;
        Object obj = null;
        try {
            httpclient = getDefaultHttpClient(requestCharset);
            hg = new HttpGet(url);
            obj = httpclient.execute(hg, handler);
        } catch (Exception e) {
        } finally {
            abortConnection(hg, httpclient);
        }
        return obj;
    }

    public static byte[] post(String url) throws Exception {
        return (byte[]) post(url, null, null, byteArrayHandler);
    }

    public static byte[] post(String url, Map<String, String> params) throws Exception {
        return (byte[]) post(url, params, null, byteArrayHandler);
    }

    //2013/12/28 renle modify
    //增加编码参数
    public static byte[] post(String url, Map<String, String> params, String charset) throws Exception {
        return (byte[]) post(url, params, charset, byteArrayHandler);
    }

    private static Object post(String url, Map<String, String> params, String requestCharset, ResponseHandler handler) {
        if (url == null || StringUtils.isEmpty(url)) {
            return null;
        }
        UrlEncodedFormEntity formEntity = null;
        List<NameValuePair> qparams = getParamsList(params);
        if (qparams != null && 0 < qparams.size()) {
            try {
                if (requestCharset == null || StringUtils.isEmpty(requestCharset)) {
                    formEntity = new UrlEncodedFormEntity(qparams);
                } else {
                    formEntity = new UrlEncodedFormEntity(qparams, requestCharset);
                }
            } catch (UnsupportedEncodingException e) {
            }
        }
        //创建HttpClient实例
        DefaultHttpClient httpclient = null;
        HttpPost hp = null;
        Object obj = null;
        try {
            httpclient = getDefaultHttpClient(requestCharset);
            hp = new HttpPost(url);
            if (formEntity != null) {
                hp.setEntity(formEntity);
            }
            obj = httpclient.execute(hp, handler);
        } catch (Exception e) {
        } finally {
            abortConnection(hp, httpclient);
        }
        return obj;
    }
    
    /**
     * post请求 传递json参数
     * 
     * @param url
     * @param jsonData
     * @return
     */
    public static String post(String url, String jsonData){
    	CloseableHttpClient client = HttpClients.createDefault();
    	HttpPost post = new HttpPost(url);
    	StringEntity strEntity = new StringEntity(jsonData, ContentType.APPLICATION_JSON);//设置请求数据
    	 post.setEntity(strEntity);// 设置请求体
    	 String responseContent = null; // 响应内容
    	 CloseableHttpResponse response = null;
    	 try{
    		 response = client.execute(post);
    		 if(response.getStatusLine().getStatusCode() == 200) {
    			 HttpEntity entity = response.getEntity();
    			 responseContent = EntityUtils.toString(entity, "UTF-8");
    		 }
    	} catch (ClientProtocolException e) {
    		logger.error("-----------------"+ JDKStackTrace.getJDKStrack(e)+"---------------------");
    	} catch (IOException e) {
    		logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    	} finally {
    		try {
    			if (response != null)
    				response.close();
    			} catch (IOException e) {
    				logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    				} finally {
    					try {
    						if (client != null)
    							client.close();
    						} catch (IOException e) {
    							e.printStackTrace();
    							logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    							}
    					}
    		}
    	return responseContent;
    }

    public static String postXML(String url, String xmlData){
    	CloseableHttpClient client = HttpClients.createDefault();
    	HttpPost post = new HttpPost(url);
    	StringEntity strEntity = new StringEntity(xmlData, ContentType.APPLICATION_XML);//设置请求数据
    	post.setEntity(strEntity);// 设置请求体
    	String responseContent = null; // 响应内容
    	CloseableHttpResponse response = null;
    	try{
			 response = client.execute(post);
			 if(response.getStatusLine().getStatusCode() == 200) {
				 HttpEntity entity = response.getEntity();
				 responseContent = EntityUtils.toString(entity, "UTF-8");
			 }
    	} catch (ClientProtocolException e) {
    		logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    	} catch (IOException e) {
    		logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    	} finally {
    		try {
    			if (response != null)
    				response.close();
    			} catch (IOException e) {
    				logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    				} finally {
    					try {
    						if (client != null)
    							client.close();
    						} catch (IOException e) {
    							e.printStackTrace();
    							logger.error("-----------------"+JDKStackTrace.getJDKStrack(e)+"---------------------");
    							}
    					}
    		}
    	return responseContent;
    }
    
    private static DefaultHttpClient getDefaultHttpClient(final String charset) {
        DefaultHttpClient httpclient = new DefaultHttpClient();
        httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
        //模拟浏览器，解决一些服务器程序只允许浏览器访问的问题
        httpclient.getParams().setParameter(CoreProtocolPNames.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)");
        httpclient.getParams().setParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, Boolean.FALSE);
        httpclient.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, charset == null ? CHARSET_UTF8 : charset);
        httpclient.setHttpRequestRetryHandler(requestRetryHandler);

        HttpParams params = httpclient.getParams();
        HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT_MILLIS);
        HttpConnectionParams.setSoTimeout(params, SOCKET_TIMEOUT_MILLIS);
        return httpclient;
    }

    private static void abortConnection(final HttpRequestBase hrb, final HttpClient httpclient) {
        if (hrb != null) {
            hrb.abort();
        }
        if (httpclient != null) {
            httpclient.getConnectionManager().shutdown();
        }
    }

    private static List<NameValuePair> getParamsList(Map<String, String> paramsMap) {
        if (paramsMap == null || paramsMap.size() == 0) {
            return null;
        }
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        for (Map.Entry<String, String> map : paramsMap.entrySet()) {
            params.add(new BasicNameValuePair(map.getKey(), map.getValue()));
        }
        return params;
    }
    
    /**
     * 下载文件到 path
     */
    /*public static void httpDownLoadFile(String url, String localFilePath){
    	 URL urlfile = null;
         HttpURLConnection httpUrl = null;
         BufferedInputStream bis = null;
         BufferedOutputStream bos = null;
         File f = new File(localFilePath);
         if(!f.isDirectory()){
        	 f.mkdir();
         }
         try{
             urlfile = new URL(url);
             httpUrl = (HttpURLConnection)urlfile.openConnection();
             httpUrl.connect();
             bis = new BufferedInputStream(httpUrl.getInputStream());
             bos = new BufferedOutputStream(new FileOutputStream(f));
             int len = 2048;
             byte[] b = new byte[len];
             while ((len = bis.read(b)) != -1)
             {
                 bos.write(b, 0, len);
             }
             bos.flush();
             bis.close();
             httpUrl.disconnect();
         }catch (Exception e){
             e.printStackTrace();
         }finally{
        	 try{
        		 bis.close();
                 bos.close();
             }catch (IOException e){
                 e.printStackTrace();
             }
         }
    }*/
    
    @SuppressWarnings({ "deprecation", "resource" })
	public static synchronized String httpDownloadFile(String url, String dirPath, String saveFileName) {  
    	logger.info("---httpDownloadFile[success] begin--");
        logger.debug("path:" + dirPath);  
        logger.debug("url:" + url);  
        HttpClient client = null;  
        try {  
            client = new DefaultHttpClient();  
            HttpGet httpGet = getHttpGet(url, null, null);  
            HttpResponse response = client.execute(httpGet); 
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {  
            	Header[] content_disposition = response.getHeaders("Content-disposition");
            	//Header[] content_disposition = response.getAllHeaders();
            	logger.debug(">>>"+content_disposition.length);
            	String cdValue = content_disposition[0].getValue();
            	String fileType = cdValue.substring(cdValue.lastIndexOf(".")+1, cdValue.length()-1);
                byte[] result = EntityUtils.toByteArray(response.getEntity());  
                BufferedOutputStream bw = null;  
                try {  
                    File dir = new File(dirPath);  
                    
                    if(!dir.isDirectory()){
                    	dir.mkdir();
                    }
                    File file = new File(dir.getAbsolutePath()+File.separatorChar+saveFileName+"."+fileType);
                    saveFileName = saveFileName+"."+fileType;
                    bw = new BufferedOutputStream(new FileOutputStream(file));  
                    bw.write(result);  
                    logger.info("---httpDownloadFile[success] end--");
                } catch (Exception e) {  
                    logger.error("保存文件错误,path=" + dirPath + ",url=" + url, e); 
                    return null;
                } finally {  
                    try {  
                        if (bw != null)  
                            bw.close();  
                    } catch (Exception e) {  
                        logger.error(  
                                "finally BufferedOutputStream shutdown close",  
                                e);  
                    }  
                }  
                return saveFileName;
            }else {  // 如果失败  
                StringBuffer errorMsg = new StringBuffer();  
                errorMsg.append("httpStatus:");  
                errorMsg.append(response.getStatusLine().getStatusCode());  
                errorMsg.append(response.getStatusLine().getReasonPhrase());  
                errorMsg.append(", Header: ");  
                Header[] headers = response.getAllHeaders();  
                for (Header header : headers) {  
                    errorMsg.append(header.getName());  
                    errorMsg.append(":");  
                    errorMsg.append(header.getValue());  
                }  
                logger.error("HttpResonse Error:" + errorMsg);
                return null;
            }  
        } catch (ClientProtocolException e) {  
            logger.error("下载文件保存到本地,http连接异常,path=" + dirPath + ",url=" + url, e);  
            logger.error("----"+JDKStackTrace.getJDKStrack(e)+"----");
        } catch (IOException e) {  
            logger.error("下载文件保存到本地,文件操作异常,path=" + dirPath + ",url=" + url, e);  
            logger.error("----"+JDKStackTrace.getJDKStrack(e)+"----");
        } finally {  
            try {  
                client.getConnectionManager().shutdown();  
            } catch (Exception e) {  
                logger.error("finally HttpClient shutdown error", e);  
                return null;
            }  
        }  
        return null;
    }  
    private static HttpGet getHttpGet(String url, Map<String, String> params,  
            String encode) {  
        StringBuffer buf = new StringBuffer(url);  
        if (params != null) {  
            // 地址增加?或者&  
            String flag = (url.indexOf('?') == -1) ? "?" : "&";  
            // 添加参数  
            for (String name : params.keySet()) {  
                buf.append(flag);  
                buf.append(name);  
                buf.append("=");  
                try {  
                    String param = params.get(name);  
                    if (param == null) {  
                        param = "";  
                    }  
                    buf.append(URLEncoder.encode(param, encode));  
                } catch (UnsupportedEncodingException e) {  
                    logger.error("URLEncoder Error,encode=" + encode + ",param="  
                            + params.get(name), e);  
                }  
                flag = "&";  
            }  
        }  
        HttpGet httpGet = new HttpGet(buf.toString());  
        return httpGet;  
    }  
    public static void main(String[] args) {
    	Date date = new Date();
    	String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=Z7qysXZTQUOTxEvfBJVA8SFZTpdVSPIEL6xSUCFp9zXXU-Hd0vp8S_t-xiLtKEe7_dzSX28wEnRh3dR2SBfAinayZejP_zMQgOaBZQRXhJs&media_id=JX62ViNJ7oFNKLKBGnRS1kWFWzUL_zofbw-txgEeskTDFLhPkTK6DLSupQzlQFDF";
		HttpClientUtils.httpDownloadFile(url, "F:/rec/", date.getTime()+"");
    	//String cdValue = "attachment; filename=\"MEDIA_ID.jpg\"";
    	//String fileType = cdValue.substring(cdValue.lastIndexOf(".")+1, cdValue.length()-1);
    	//System.out.println(fileType);
	}
}
